import { _decorator, Component, Node } from 'cc';
import { Ball } from './Ball';
import { PlayBaseUser } from './PlayBaseUser';
import { Cue } from './Cue';
import { GameBaseModel } from './GameBaseModel';
import { EventConst } from '../../common/Common';
import { find } from 'cc';
import { App } from '../../App';
import UtilTool from '../../tools/UtilTool';
import { BLACK_BALL, WHITE_BALL } from './GameManage';
import { Role } from './Role';
import { showTip } from '../../tools/PopuUp';
import { Vec3 } from 'cc';
import { RigidBody } from 'cc';
import { PD } from '../../player/PlayerData';
const { ccclass, property } = _decorator;

// 游戏状态机状态
export enum GamePlayState {
    NONE,
    GAME_START, // 游戏开始
    WAIT_HIT_BALL, // 等待击球
    HIT_BALL, // 击球
    HIT_BALL_END, // 击球结束
    WAIT_POS_BALL, // 等待摆球
    POS_BALL_END, // 摆球结束
    ONE_ROUND_END, // 一轮结束
    GAME_END, // 游戏结束
}

// 游戏结束状态
export enum GameEndState {
    NONE,
    FAIL,
    WIN,
}

// 游玩时的一些提示信息
export enum GamePlayTip {
    GAME_START, // 游戏开始
    COLOR_SET, // 选定花球，继续击球
    FOUL_CHANGE, // 击球犯规，交换选手
    NORMAL_CHANGE, // 普通击球，交换选手
    COMB, // 连杠
    POS_BALL_TIME_END, // 摆球时间结束
    HIT_BALL_TIME_END, // 击球时间结束
    GAME_END, // 游戏结束

    GAME_RESET_ALLBALL, // 击球犯规，重置所有球
    GAME_MORA_WIN, // XXX猜拳胜利，开始击球
}

export class GameBaseLogic {

    curPlayUser : PlayBaseUser = null

    isHasSetBallBelogn : boolean = false // 是否决定球的归属

    ballInRoleList : number[] = [] // 进球列表

    roleInballList : number[] = [] // 进球的洞列表

    areaCollideList : number[] = [] // 触碰到的得分区域编号列表

    contactBallList : number[] = [] // 白球的碰球列表

    whiteBallCtrl : Ball = null // 白球

    comboCount : number = 0 // 连杆数

    playWheel : number = 0 // 当前击打第几轮

    uploadAccount : string = "" // 负责上报帧数据的玩家

    isQuickGame : number = 0 // 注：当前是否是决战时刻（四球开伦） 0否 1是

    curPlayState : GamePlayState = GamePlayState.NONE
    beforePlayState : GamePlayState = GamePlayState.NONE

    gameEndState : GameEndState = GameEndState.NONE // 游戏结束状态 -1:未结束 0:输 1:赢

    cue : Cue = null

    curComboClearBallList = [] // 当前一直连杠打进的球列表

    gameView : GameBaseModel = null

    constructor() {
        this.init()
    }

    init() {
        App.Model.gameLogic = this
        let game3d : Node = find("gameNode/game_3d")
        // this.cue = game3d.getComponentInChildren(Cue)
        this.cue = find("Canvas/viewNode/cueNode2d").getComponent(Cue)

        this.whiteBallCtrl = find("gameNode/game_3d/whiteball").getComponent(Ball)
        
        App.Event.on(EventConst.ACTION_TIME_END, this.downTimeEndEvent, this)
        App.Event.on(EventConst.GAME_ABEL_BALL, this.setAbelBall, this)
        
    }

    onGameStart() {

    }

    // 收到球进洞事件
    ballInRoleEvent(ballNumber : number, ballNode : Node, role : Role) {
        this.ballInRoleList.push(ballNumber)
        
        // 播放进球动画
        if(ballNumber != WHITE_BALL) { 
            if(ballNumber == BLACK_BALL) {
                let curBallList = this.curPlayUser.ballList
                if(curBallList.length == 1 && curBallList[0] == BLACK_BALL) { // 只有一个球的情况
                    role.playInRoleAnim()
                }
            } else {
                role.playInRoleAnim()
            }
        }

        this.updateBallInfo()

    }

    // 收到开始击球事件
    startHitBallEvent(event) {
        this.setPlayState(GamePlayState.HIT_BALL)
    }

    // 收到白球的碰撞事件
    whiteBallContactEvent(ballNumber : number) {
        if (this.contactBallList.indexOf(ballNumber)==-1) {
            this.contactBallList.push(ballNumber)
        }
    }

    // 收到摆球结束事件
    whiteBallPosEndEvent(whiteBallPos) {
        this.whiteBallCtrl.setWhiteBall(whiteBallPos)
        this.curPlayUser.onCue()
        this.setPlayState(GamePlayState.POS_BALL_END)
    }

    // 收到击球结束事件
    hitBallEndEvent() {
        if (this.curPlayState == GamePlayState.GAME_END) {
            // 游戏结束后就不需要再走后面的流程了
            return
        }

        this.setPlayState(GamePlayState.HIT_BALL_END)
    }

    // 更新UI上的球的信息
    updateBallInfo() {
    }

    // 收到倒计时时间结束事件
    downTimeEndEvent() {
        // 在子类里面去处理自己的事情
    }

    // 清除当前的状态
    clearState() {
        this.gameView.cueCtrl.clearState()
        this.stopActionTime()
    }

    // 停止计时
    stopActionTime() {
        UtilTool.printLog("not extends stopActionTime")
    }

    setPlayState(playState : GamePlayState) {

        this.beforePlayState = this.curPlayState
        this.curPlayState = playState

        this.clearState()
        
        UtilTool.printLog("cur play state ", this.getName(),  this.getPlayStateDesc(this.curPlayState))

        let stateText = UtilTool.formatStr("玩家%s:%s", this.getName(), this.getPlayStateDesc(this.curPlayState))
        // this.gameLayer.setGameState(stateText)

        switch(playState) {

            case GamePlayState.GAME_START: // 游戏开始
                this.onGameStart()
                break

            case GamePlayState.WAIT_HIT_BALL: // 等待击球
                this.onWaitHitBall()
                break

            case GamePlayState.WAIT_POS_BALL: // 等待摆球
                this.onWaitPosBall()
                break

            case GamePlayState.POS_BALL_END: // 摆球结束
                this.onPosBallEnd()
                break
            
            case GamePlayState.ONE_ROUND_END: // 一轮结束
                this.onOneRoundEnd()
                break

            case GamePlayState.HIT_BALL: // 击球
                this.onHitBall()
                break

            case GamePlayState.HIT_BALL_END: // 击球结束
                this.onHitBallEnd()
                break

            case GamePlayState.GAME_END: // 游戏结束
                this.onGameEnd()
                break
        }
        
    }

    getName() {
        return this.curPlayUser.getName()
    }

    // 游戏结束
    onGameEnd() {
        UtilTool.printLog("not extends onGameEnd")
    }

    // 击球结束
    onHitBallEnd() {
        UtilTool.printLog("not extends onHitBallEnd")
    }

    // 击球
    onHitBall() {
        UtilTool.printLog("not extends onHitBall")
    }

    // 一轮结束
    onOneRoundEnd() {
        UtilTool.printLog("not extends onOneRoundEnd")
    }

    // 摆球结束
    onPosBallEnd() {
        UtilTool.printLog("not extends onPosBallEnd")
    }

    // 等待摆球
    onWaitPosBall() {
        UtilTool.printLog("not extends onWaitPosBall")
    }

    // 等待击球
    onWaitHitBall() {
        UtilTool.printLog("not extends onWaitHitBall")
    }

    getPlayStateDesc(state : GamePlayState) {
    
        switch(state) {
            case GamePlayState.NONE:
                return "NONE"
            case GamePlayState.GAME_START:
                return "游戏开始"
            case GamePlayState.WAIT_HIT_BALL:
                return "等待击球"
            case GamePlayState.HIT_BALL:
                return "击球"
            case GamePlayState.HIT_BALL_END:
                return "击球结束"
            case GamePlayState.WAIT_POS_BALL:
                return "等待摆球"
            case GamePlayState.POS_BALL_END:
                return "摆球结束"
            case GamePlayState.ONE_ROUND_END:
                return "一轮结束"
            case GamePlayState.GAME_END:
                return "游戏结束"
        }
        
        return "NONE"
    
    }

    // 切换玩家
    changePlay(address = "") {
        this.comboCount = 0
        this.curComboClearBallList.length = 0
    }

    /**检查是否犯规
     *  a.母球落袋； 
        b.母球没有碰到其它球；
        C.母球碰到的第一个球不是己方花色；
        犯规一律由对手罚任意球，即，将母球摆在任意位置向任意方向击球。
        isCurRoundSetBelogin: 是否当前回合设置了归属球
     */
    checkIsFoul(isCurRoundSetBelogn : boolean) : number {

        UtilTool.printLog("cur checkIsFoul", this.ballInRoleList)

        let foulType = 0 // 犯规的类型 [0]不犯规 [1]母球没有碰到其它球 [2]母球碰到的第一个球不是己方花色 [3]母球落袋 (以下犯规的判断顺序不能改，会影响到服务器的判断)

        // c:母球碰到的第一个球不是己方花色；
        if(this.isHasSetBallBelogn && !isCurRoundSetBelogn && this.contactBallList.length>0) {
            let firstContactBall = this.contactBallList[0]
            let isBeloginMine = this.curPlayUser.isBelognMine(firstContactBall)
            
            if(!isBeloginMine) {
                UtilTool.printLog("cur play state ", this.getName(), "犯规 碰到的不是己方花色")
                foulType = 2
                return foulType
            } 
        }

        // a:母球落袋； 
        let isWhiteBallInRole = this.ballInRoleList.includes(0)
        if(isWhiteBallInRole) {
            UtilTool.printLog("cur play state ", this.getName(), "犯规 母球落袋")
            foulType = 3
            return foulType
        }

        // b:母球没有碰到其它球；
        if(this.contactBallList.length == 0) {
            UtilTool.printLog("cur play state ", this.getName(), "犯规 母球没有碰到其它球")
            foulType = 1
            return foulType
        }

        return foulType
    }

    // 显示游玩中的提示信息
    showPlayTip(gamePlayTip : GamePlayTip, data=null) {
        let text = ""
        switch(gamePlayTip) {
            case GamePlayTip.GAME_START:
                text = App.language.getLanguageLab(97)
                break
            case GamePlayTip.COLOR_SET:
                text = App.language.getLanguageLab(98)
                break
            case GamePlayTip.FOUL_CHANGE:
                text = App.language.getLanguageLab(99)
                break
            case GamePlayTip.NORMAL_CHANGE:
                text = App.language.getLanguageLab(100)
                break
            case GamePlayTip.COMB: // 连杆
                // text = UtilTool.formatStr(App.language.getLanguageLab(101), data)
                this.showCombo(data)
                break

            case GamePlayTip.POS_BALL_TIME_END: 
                text = App.language.getLanguageLab(102)
                break

            case GamePlayTip.HIT_BALL_TIME_END:
                text = App.language.getLanguageLab(103)
                break

            case GamePlayTip.GAME_END:
                text = App.language.getLanguageLab(104)
                break

            case GamePlayTip.GAME_RESET_ALLBALL:
                text = App.language.getLanguageLab(140)
                break

            case GamePlayTip.GAME_MORA_WIN:
                // text = UtilTool.formatStr(App.language.getLanguageLab(166), UtilTool.getShortWalletAddr(App.Model.gameManage.gameStartData.currentHitPlayer))

                let address = ""
                let nickname = ""

                if (App.fightMode == App.fightMode_4){
                    address = App.Model.gameManage.gameStartBloodData.currentHitPlayer
                    nickname = App.Model.gameManage.gameStartBloodData.nicknameMap[address]
                }
                else if (App.fightMode == App.fightMode_3) {
                    address = App.Model.gameManage.gameStartData.currentHitPlayer
                    nickname = App.Model.gameManage.gameStartData.nicknameMap[address]
                }
                
                text = UtilTool.formatStr(App.language.getLanguageLab(166), UtilTool.formatNickOrAddress({"nickname":nickname, "address":address}))
                break
        }
        
        if(text != "") {
            showTip(text)
        }

    }

    // 设置呼吸效果
    setAbelBall(show=false) {
    }

    // 是否是自己的账号
    isMineAccount(account) {
        return PD.user.addressUrl == account
    }

    /** 获取所有球的位置信息 */
    getAllBallPos() {
        if(App.Model.gameView==null) {
            return
        }
        
        let whiteBall = (App.Model.gameView as GameBaseModel).whiteBall
        let otherBallList  = App.Model.gameManage.otherBallArr

        let linearVelocity = new Vec3()
        whiteBall.getComponent(RigidBody).getLinearVelocity(linearVelocity)
        let rangle = new Vec3()
        whiteBall.getComponent(RigidBody).getAngularVelocity(rangle)

        let ballList = []
        ballList.push(
            {
                num:this.whiteBallCtrl.number, 
                posX:UtilTool.formatDigits(whiteBall.worldPosition.x), 
                // posY:UtilTool.formatDigits(whiteBall.worldPosition.y), 
                posZ: UtilTool.formatDigits(whiteBall.worldPosition.z), 
                visible:this.whiteBallCtrl.node.active,
                angle:[UtilTool.formatDigits(this.whiteBallCtrl.node.eulerAngles.x), UtilTool.formatDigits(this.whiteBallCtrl.node.eulerAngles.y), UtilTool.formatDigits(this.whiteBallCtrl.node.eulerAngles.z)],
                dynamics:[UtilTool.formatDigits(linearVelocity.x), UtilTool.formatDigits(linearVelocity.y), UtilTool.formatDigits(linearVelocity.z)],
                angular:[UtilTool.formatDigits(rangle.x), UtilTool.formatDigits(rangle.y), UtilTool.formatDigits(rangle.z)]
            }
        )

        otherBallList.forEach((ball) => {
            let number = ball.getComponent(Ball).number
            let eulerAngles = ball.getComponent(Ball).node.eulerAngles
            let linearVelocity2 = new Vec3()
            ball.getComponent(RigidBody).getLinearVelocity(linearVelocity2)
            let rangle2 = new Vec3()
            ball.getComponent(RigidBody).getAngularVelocity(rangle2)

            ballList.push(
                {
                    num:number, 
                    posX:UtilTool.formatDigits(ball.worldPosition.x), 
                    // posY:UtilTool.formatDigits(ball.worldPosition.y), 
                    posZ: UtilTool.formatDigits(ball.worldPosition.z), 
                    visible:ball.getComponent(Ball).node.active,
                    angle:[UtilTool.formatDigits(eulerAngles.x), UtilTool.formatDigits(eulerAngles.y), UtilTool.formatDigits(eulerAngles.z)],
                    dynamics:[UtilTool.formatDigits(linearVelocity2.x), UtilTool.formatDigits(linearVelocity2.y), UtilTool.formatDigits(linearVelocity2.z)],
                    angular:[UtilTool.formatDigits(rangle2.x), UtilTool.formatDigits(rangle2.y), UtilTool.formatDigits(rangle2.z)]
                })
        })

        // let text = JSON.stringify(ballList)
        // UtilTool.printLog("获取每个球的位置信息 ", text)

        return ballList
    }

    /** 矫正所有球的位置信息 */
    modifyAllBallPos(allBallInfo,isFrame = false) {
        if (allBallInfo.length <= 0) {
            return
        }

        if(App.Model.gameView==null) {
            return
        }

        let whiteBall = (App.Model.gameView as GameBaseModel).whiteBall
        let otherBallList  = App.Model.gameManage.otherBallArr

        let allBallList = []    // 包括母球的所有球的列表
        allBallList.push(whiteBall)
        otherBallList.forEach(ball => {
            allBallList.push(ball)
        });

        // 遍历所有的球并矫正位置
        allBallInfo.forEach((ballInfo) => {
            let ball = allBallList.filter(item => {
                let ballNumber = item.getComponent(Ball).number
                return ballNumber == ballInfo.num
            })

            if (!ballInfo.visible) {
                if (ball[0]) {
                    ball[0].getComponent(Ball).hide()
                }
            }else {
                if (ball[0]) {
                    ball[0].getComponent(Ball).node.active = true
                    ball[0].getComponent(Ball).node.worldPosition = new Vec3(ballInfo.posX, Ball.BALL_STATIC_Y/* ballInfo.posY */, ballInfo.posZ)
                    ball[0].getComponent(Ball).node.setRotationFromEuler(ballInfo.angle[0], ballInfo.angle[1], ballInfo.angle[2])

                    if (isFrame) {
                        ball[0].getComponent(RigidBody).clearState()
                        ball[0].getComponent(RigidBody).setLinearVelocity(new Vec3(ballInfo.dynamics[0], ballInfo.dynamics[1], ballInfo.dynamics[2]))
                        ball[0].getComponent(RigidBody).setAngularVelocity(new Vec3(ballInfo.angular[0], ballInfo.angular[1], ballInfo.angular[2]))
                    }
                    
                    // UtilTool.printLog("矫正",ball[0].getComponent(Ball).number)
                }
            }
        })
    }

    /** 通过球号获取球的信息 */
    getBallInfoByNumber(num) {
        let allBallInfo = []
        if (App.fightMode == App.fightMode_4) {
            allBallInfo = App.Model.gameManage.gameStartBloodData.allBallInfo
        }

        for (let i = 0; i < allBallInfo.length; i++) {
            let item = allBallInfo[i]
            if (item.num == num) {
                return item
            }
        }

        return null
    }


    /** 通知玩家当前房间内游戏状态 */
    respGameStatusChange(data) {
    }

    /** 通知游戏断线重连 */
    respGameReconnect(gamedata) {

    }

    showCombo(comboCount : number) {
    }

    onDestroy() {
        App.Event.off(EventConst.ACTION_TIME_END, this.downTimeEndEvent, this)
        App.Event.off(EventConst.GAME_ABEL_BALL, this.setAbelBall, this)
    }

}

